package com.neusoft.bizcore.activiti.service.impl;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.activiti.constants.BizcoreActivitiConstants;
import com.neusoft.bizcore.activiti.converter.ActSerialNumberConverter;
import com.neusoft.bizcore.activiti.dto.ActSerialNumberDTO;
import com.neusoft.bizcore.activiti.model.ActSerialNumber;
import com.neusoft.bizcore.activiti.repository.ActSerialNumberRepository;
import com.neusoft.bizcore.activiti.service.ISerialNumService;

@Service
public class ActSerialNumberServiceImpl implements ISerialNumService {

    @Autowired
    private ActSerialNumberRepository serialNumberRepository;
    @Autowired
    private ActSerialNumberConverter serialNumberConverter;

    /** 格式 */
    private String pattern = "";

    /** 生成器锁 */
    private final ReentrantLock lock = new ReentrantLock();

    /** 流水号格式化器 */
    private DecimalFormat format = null;

    /** 预生成锁 */
    private final ReentrantLock prepareLock = new ReentrantLock();

    /** 最小值 */
    private int min = 0;

    /** 最大值 */
    private long max = 0;

    /** 已生成流水号（种子） */
    private long seed = this.min;

    /** 预生成数量 */
    private int prepare = 0;

    /** 数据库存储的当前最大序列号 **/
    long maxSerialInt = 0;

    /** 当前序列号是否为个位数自增的模式 **/
    private String isAutoIncrement = "0";

    ActSerialNumberDTO systemSerialNumberDTO = new ActSerialNumberDTO();

    /** 预生成流水号 */
    HashMap<String, List<String>> prepareSerialNumberMap = new HashMap<>();

    /**
     * 根据模块code生成预数量的序列号存放到Map中
     *
     * @param moduleCode 模块code
     * @return
     */
    @CachePut(value = "serialNumber", key = "#moduleCode")
    public List<String> generatePrepareSerialNumbers(final String moduleCode) {
        //临时List变量
        final List<String> resultList = new ArrayList<>(this.prepare);
        this.lock.lock();
        try {
            for (int i = 0; i < this.prepare; i++) {
                this.maxSerialInt = this.maxSerialInt + 1;
                if ((this.maxSerialInt > this.min) && ((this.maxSerialInt + "").length() < this.max)) {
                    this.seed = this.maxSerialInt;
                } else {
                    //如果动态数字长度大于模板中的长度 例：模板CF000  maxSerialInt 1000
                    this.seed = this.maxSerialInt = 0;
                    //更新数据，重置maxSerialInt为0
                    this.systemSerialNumberDTO.setMaxSerial("0");
                    final ActSerialNumber systemSerialNumber =
                            this.serialNumberConverter.toModel(this.systemSerialNumberDTO);
                    this.serialNumberRepository.save(systemSerialNumber);
                }
                //动态数字生成
                String formatSerialNum = this.format.format(this.seed);

                //动态日期的生成
                if (this.pattern.contains(BizcoreActivitiConstants.DATE_SYMBOL)) {
                    final String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
                    formatSerialNum = formatSerialNum.replace(BizcoreActivitiConstants.DATE_SYMBOL, currentDate);
                }

                resultList.add(formatSerialNum);
            }
            //更新数据
            this.systemSerialNumberDTO.setMaxSerial(this.maxSerialInt + "");
            final ActSerialNumber systemSerialNumber = this.serialNumberConverter.toModel(this.systemSerialNumberDTO);
            this.serialNumberRepository.save(systemSerialNumber);
        } finally {
            this.lock.unlock();
        }
        return resultList;
    }

    /**
     * 根据模块code生成序列号
     *
     * @param moduleCode 模块code
     * @return 序列号
     */
    @Override
    public String generateSerialNumberByModelCode(final String moduleCode) {

        //预序列号加锁
        this.prepareLock.lock();
        try {
            //判断内存中是否还有序列号
            if ((null != this.prepareSerialNumberMap.get(moduleCode))
                    && (this.prepareSerialNumberMap.get(moduleCode).size() > 0)) {
                //若有，返回第一个，并删除
                return this.prepareSerialNumberMap.get(moduleCode).remove(0);
            }
        } finally {
            //预序列号解锁
            this.prepareLock.unlock();
        }
        final ActSerialNumber model = this.serialNumberRepository.findByModuleCode(moduleCode);
        this.systemSerialNumberDTO = this.serialNumberConverter.toDTO(model);
        this.prepare = Integer.parseInt(this.systemSerialNumberDTO.getPreMaxNum().trim());//预生成流水号数量
        this.pattern = this.systemSerialNumberDTO.getConfigTemplet().trim();//配置模板
        final String maxSerial = this.systemSerialNumberDTO.getMaxSerial().trim(); //存储当前最大值
        this.isAutoIncrement = this.systemSerialNumberDTO.getIsAutoIncrement().trim();
        this.maxSerialInt = Long.parseLong(maxSerial.trim());//数据库存储的最大序列号
        this.max = this.counter(this.pattern, '0') + 1;//根据模板判断当前序列号数字的最大值
        if (this.isAutoIncrement.equals("1")) {
            this.pattern = this.pattern.replace("0", "#");
        }
        this.format = new DecimalFormat(this.pattern);
        //生成预序列号，存到缓存中
        final List<String> resultList = this.generatePrepareSerialNumbers(moduleCode);
        this.prepareLock.lock();
        try {
            this.prepareSerialNumberMap.put(moduleCode, resultList);
            return this.prepareSerialNumberMap.get(moduleCode).remove(0);
        } finally {
            this.prepareLock.unlock();
        }
    }

    /**
     * 设置最小值
     *
     * @param value 最小值，要求：大于等于零
     * @return 流水号生成器实例
     */
    @Override
    public ISerialNumService setMin(final int value) {
        this.lock.lock();
        try {
            this.min = value;
        } finally {
            this.lock.unlock();
        }
        return this;
    }

    /**
     * 最大值
     *
     * @param value 最大值，要求：小于等于Long.MAX_VALUE ( 9223372036854775807 )
     * @return 流水号生成器实例
     */
    @Override
    public ISerialNumService setMax(final long value) {
        this.lock.lock();
        try {
            this.max = value;
        } finally {
            this.lock.unlock();
        }
        return this;
    }

    /**
     * 设置预生成流水号数量
     *
     * @param count 预生成数量
     * @return 流水号生成器实例
     */
    @Override
    public ISerialNumService setPrepare(final int count) {
        this.lock.lock();
        try {
            this.prepare = count;
        } finally {
            this.lock.unlock();
        }
        return this;
    }

    /**
     * 统计某一个字符出现的次数
     *
     * @param str 查找的字符
     * @param c
     * @return
     */
    private int counter(final String str, final char c) {
        int count = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == c) {
                count++;
            }
        }
        return count;
    }

}
